| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- import clsx from "clsx";
- import { GetServerSideProps } from "next";
- import Link from "next/link";
- import { useRouter } from "next/router";
- import { ReactElement, useState } from "react";
- import Footer from "../../../components/common/Footer";
- import Header from "../../../components/common/Header";
- import NovelCover from "../../../components/NovelCover";
- import styles from "../../../styles/chapter.module.scss";
- import { ChapterData, ChapterListData } from "../../../types/http";
- import useGet from "../../../utils/hooks/useGet";
- import { get } from "../../../utils/http";
- import type { NextPageWithLayout } from "../../_app";
- import toggleTheme from "../../../libs/toggleTheme";
- import Settings from "../../../components/novel/Settings";
- import Toolbar from "../../../components/novel/Toolbar";
- import Toc from "../../../components/novel/Toc";
- const Chapter: NextPageWithLayout = () => {
- const { query } = useRouter();
- const { data: chapterData = null } = useGet<ChapterData>(
- `/api/novel/chapter/${query.slug}/${query.chapter}`
- );
- // const { data: { data: chapterData } = { data: null } } = useGet<ChapterData>(
- // `/api/novel/chapter/${query.slug}/${query.chapter}`
- // );
- const [open, setOpen] = useState(false);
- const [menu, setMenu] = useState("");
- const [isSerif, setIsSerif] = useState(
- JSON.parse(
- typeof localStorage !== "undefined" &&
- localStorage.getItem("novelIsSerif")
- ? localStorage.getItem("novelIsSerif") || "false"
- : "false"
- ) as boolean
- );
- const [fontSize, setFontSize] = useState(
- Number(
- typeof localStorage !== "undefined" &&
- localStorage.getItem("novelFontSize")
- ? localStorage.getItem("novelFontSize")
- : "3"
- )
- );
- const handleOpenToolbar = () => {
- if (open) {
- setOpen(false);
- setMenu("");
- } else {
- setOpen(true);
- }
- };
- const handleChangeSettings = (type: string = "") => {
- if (menu === type) {
- setMenu("");
- } else {
- setOpen(true);
- setMenu(type);
- }
- };
- const handleStopPropagation = (e: React.MouseEvent) => {
- e.stopPropagation();
- };
- const handleSetIsSerif = (isSerif: boolean) => {
- localStorage.setItem("novelIsSerif", JSON.stringify(isSerif));
- setIsSerif(isSerif);
- };
- const handleSetFontSize = (size: number) => {
- localStorage.setItem("novelFontSize", `${size}`);
- setFontSize(size);
- };
- if (!chapterData) {
- return null;
- }
- return (
- <>
- <header
- className={clsx("header", styles["chapter-header"], {
- [styles["open"]]: open,
- })}
- >
- <Link href="/" className="logo mr-2" title="NovelDit">
- {/* eslint-disable-next-line @next/next/no-img-element */}
- <img src="/logo.svg" alt="NovelDit" />
- </Link>
- <div className="flex-1">
- <div className="text-base breadcrumbs">
- <ul>
- <li>
- <Link href={`/novel/${query.slug}`}>{chapterData.title}</Link>
- </li>
- <li>{chapterData.chapter}</li>
- </ul>
- </div>
- </div>
- {/* <div className="buttons">
- <button className="btn" onClick={() => toggleTheme()}>
- <svg className="icon-sun" viewBox="0 0 16 16">
- <use href="/icons.svg#sun"></use>
- </svg>
- <svg className="icon-moon" viewBox="0 0 16 16">
- <use href="/icons.svg#moon"></use>
- </svg>
- </button>
- </div> */}
- </header>
- <main className={styles["chapter-main"]} onClick={handleOpenToolbar}>
- <div
- className={clsx(styles["chapter-page"], {
- [styles["serif"]]: isSerif,
- "text-sm": fontSize === 1,
- "text-base": fontSize === 2,
- "text-lg": fontSize === 3,
- "text-xl": fontSize === 4,
- "text-2xl": fontSize === 5,
- })}
- >
- <article className={styles["novel"]}>
- <header>
- <h1 className="">{chapterData.title}</h1>
- <h2 className="">{chapterData.chapter}</h2>
- </header>
- <div
- className="content"
- dangerouslySetInnerHTML={{ __html: chapterData.content }}
- />
- </article>
- </div>
- <div
- className={clsx(styles["toolbar-display"], {
- hidden: !menu,
- })}
- onClick={handleStopPropagation}
- >
- {menu === "settings" ? (
- <Settings
- isSerif={isSerif}
- fontSize={fontSize}
- changeIsSerif={handleSetIsSerif}
- changeFontSize={handleSetFontSize}
- />
- ) : null}
- {menu === "toc" ? (
- <Toc
- novel={query.slug as string}
- chapter={query.chapter as string}
- />
- ) : null}
- </div>
- </main>
- <Toolbar open={open} onChangeSettings={handleChangeSettings} />
- </>
- );
- };
- Chapter.getLayout = (page: ReactElement) => page;
- export const getServerSideProps: GetServerSideProps<
- { fallback: { [key: string]: any } },
- { slug: string; chapter: string }
- > = async (context) => {
- if (!context.params) {
- return {
- props: {
- fallback: {},
- },
- };
- }
- const { slug, chapter } = context.params;
- const [chapterData, chapters] = await Promise.all([
- get<ChapterData>(
- `https://novels.yergoo.com/api/novel/chapter/${slug}/${chapter}`
- ),
- get<ChapterListData>(
- `https://novels.yergoo.com/api/novel/${slug}/chapters`
- ),
- ]);
- return {
- props: {
- fallback: {
- [`/api/novel/chapter/${slug}/${chapter}`]: chapterData,
- [`/api/novel/${slug}/chapters`]: chapters,
- },
- },
- };
- };
- export default Chapter;
|